Skip to content

Conversation

@vjsingh1984
Copy link
Contributor

Overview

This PR adds opt-in TCP_NODELAY support for low-latency trading applications. When enabled via the IBAPI_TCP_NODELAY=1 environment variable, Nagle's algorithm is disabled on all TcpStream connections, eliminating up to 40ms of latency on small writes.

Closes #390

What Changed

  • Async path: Added socket.set_nodelay(true)? in AsyncConnection::connect_with_callback() and reconnect()
  • Sync path: Added stream.set_nodelay(true)? in TcpSocket::new() and reconnect()
  • ~18 lines added total across 2 files

Backward Compatibility

100% backward compatible:

  • Default behavior unchanged (Nagle enabled)
  • Opt-in via IBAPI_TCP_NODELAY=1 environment variable
  • No API changes
  • All 100 existing unit tests pass

Usage

// Before connection
std::env::set_var("IBAPI_TCP_NODELAY", "1");
let client = Client::connect("127.0.0.1:4002", 1).await?;

Performance Impact

For trading systems:

  • Order submissions: 0-40ms latency reduction (small writes sent immediately)
  • Market data requests: Same benefit
  • Bandwidth: Negligible impact at trading message rates (~1-10 msg/sec)
  • Bulk data: Unaffected (historical bars are recv, not send)

Testing

  • All 100 existing unit tests pass
  • Manual testing confirmed with live TWS connection
  • Tested both sync and async paths

Optionally disables Nagle's algorithm on TcpStream when the environment
variable IBAPI_TCP_NODELAY=1 is set. Default behavior is unchanged
(Nagle enabled, matching upstream).

When enabled, small writes (order submissions ~100-200 bytes) are sent
immediately instead of being buffered up to 40ms. For trading systems
this eliminates latency on order routing with zero practical downside.

Usage:
  IBAPI_TCP_NODELAY=1 ./my-trading-app

Affected paths:
- sync: TcpSocket::new() and TcpSocket::reconnect()
- async: AsyncConnection::connect_with_callback() and reconnect()
Adds 10-minute bar size to the BarSize enum for historical data fetching,
matching IBKR TWS/Gateway API support.

Changes:
- Add Min10 variant to BarSize enum (between Min5 and Min15)
- Display format: "10 mins"
- FromStr parsing: "MIN10" → BarSize::Min10
- Update tests to include Min10 coverage

This aligns with the official IBKR API specification which supports
10-minute bars for historical data requests.
IBKR returns bar dates as 'YYYYMMDD  HH:MM:SS' (with two spaces)
but the parser only handled:
1. Exactly 8 characters ('YYYYMMDD')
2. Unix timestamps

This caused parsing errors like 'the year component could not be parsed'
for many symbols during warmup.

Fix: Add support for parsing dates with time component in the
IBKR-specific format (two spaces between date and time).

Related: Live trading warmup failures on Windows
@wboayue wboayue closed this Feb 9, 2026
@wboayue
Copy link
Owner

wboayue commented Feb 9, 2026

Superseded by #394

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: add opt-in TCP_NODELAY support for low-latency trading

2 participants